package tech.dort.dortware.impl.modules.exploit;

import com.google.common.eventbus.Subscribe;
import net.minecraft.entity.player.PlayerCapabilities;
import net.minecraft.network.Packet;
import net.minecraft.network.play.client.*;
import net.minecraft.network.play.server.S08PacketPlayerPosLook;
import tech.dort.dortware.api.module.Module;
import tech.dort.dortware.api.module.ModuleData;
import tech.dort.dortware.api.property.impl.BooleanValue;
import tech.dort.dortware.api.property.impl.EnumValue;
import tech.dort.dortware.api.property.impl.interfaces.INameable;
import tech.dort.dortware.impl.events.PacketEvent;
import tech.dort.dortware.impl.events.UpdateEvent;
import tech.dort.dortware.impl.utils.networking.PacketRunnableWrapper;
import tech.dort.dortware.impl.utils.networking.PacketSleepThread;
import tech.dort.dortware.impl.utils.networking.PacketUtil;
import tech.dort.dortware.impl.utils.networking.ServerUtils;
import tech.dort.dortware.impl.utils.player.ChatUtil;
import tech.dort.dortware.impl.utils.time.Stopwatch;

import java.util.concurrent.ConcurrentLinkedQueue;

public class Disabler extends Module {

    private final Stopwatch stopwatch = new Stopwatch();
    private final ConcurrentLinkedQueue<Packet> packetQueue = new ConcurrentLinkedQueue<>();

    public final EnumValue<Mode> enumValue = new EnumValue<>("Mode", this, Disabler.Mode.values());
    public final BooleanValue combatPulse = new BooleanValue("Verus Combat Pulse", this, false);
    public final BooleanValue debug = new BooleanValue("Flag Debug", this, false);
    private float verusYaw, verusPitch;

    public Disabler(ModuleData moduleData) {
        super(moduleData);
        register(enumValue, combatPulse, debug);
    }

    @Subscribe
    public void onUpdate(UpdateEvent event) {
        Mode mode = enumValue.getValue();

        switch (mode) {
            case FAITHFUL: {
                if (stopwatch.timeElapsed(3500L)) {
                    if (!packetQueue.isEmpty()) {
                        PacketUtil.sendPacketNoEvent(packetQueue.poll());
                    }
                    stopwatch.resetTime();
                }
                break;
            }

            case WATCHDOG:
                if (mc.thePlayer.ticksExisted < 5) {
                    packetQueue.clear();
                }

                if (stopwatch.timeElapsed(2000L)) {
                    while (packetQueue.size() > 20)
                        PacketUtil.sendPacketNoEvent(packetQueue.poll());
                    stopwatch.resetTime();
                }
                break;

            case SENTINEL:
                PlayerCapabilities playerCapabilities = new PlayerCapabilities();
                playerCapabilities.setFlySpeed(11);
                playerCapabilities.allowFlying = true;
                playerCapabilities.isFlying = true;
                PacketUtil.sendPacketNoEvent(new C13PacketPlayerAbilities(playerCapabilities));
                PacketUtil.sendPacketNoEvent(new C0CPacketInput());
                break;

            case VERUS:
                if (mc.thePlayer.ticksExisted % 33 == 0 && event.isPre()) {
                    if (!packetQueue.isEmpty()) {
                        PacketUtil.sendPacketNoEvent(packetQueue.poll());
                    }
                }
                if (stopwatch.timeElapsed(16600L)) {
                    while (!packetQueue.isEmpty()) {
                        PacketUtil.sendPacketNoEvent(packetQueue.poll());
                    }
                    PacketUtil.sendPacketNoEvent(new C03PacketPlayer.C04PacketPlayerPosition());
                    stopwatch.resetTime();
                }
                break;
            case VERUS_COMBAT:
                if (this.combatPulse.getValue()) {
                    if (mc.thePlayer.ticksExisted % 35 == 0) {
                        if (!packetQueue.isEmpty()) {
                            PacketUtil.sendPacketNoEvent(packetQueue.poll());
                        }
                    }
                }
                break;
            case LUNAR:
                if (mc.thePlayer.ticksExisted % 16 == 0 && !event.isPre())
                    while (!packetQueue.isEmpty()) {
                        PacketUtil.sendPacketNoEvent(packetQueue.poll());
                    }
                break;
        }
    }

    @Subscribe
    public void onPacket(PacketEvent event) {
        Mode mode = enumValue.getValue();
        if (mode.equals(Mode.SENTINEL)) {
            if (event.getPacket() instanceof C00PacketKeepAlive || event.getPacket() instanceof C0FPacketConfirmTransaction)
                event.setCancelled(true);
            return;
        }
        if (mode.equals(Mode.AAC)) {
            PacketRunnableWrapper.aacExploit.accept(event);
            return;
        }
        if (!packetQueue.isEmpty() && mc.thePlayer != null && mc.thePlayer.ticksExisted <= 11)
            packetQueue.clear();
        try {
            switch (event.getPacketDirection()) {
                case OUTBOUND:
                    switch (mode) {
                        case VERUS2:
                            if (event.getPacket() instanceof C0FPacketConfirmTransaction) {
                                packetQueue.add(event.getPacket());
                                event.setCancelled(true);
                            }
                            if (event.getPacket() instanceof C0BPacketEntityAction) {
                                event.setCancelled(true);
                            }
                            if (event.getPacket() instanceof C03PacketPlayer) {
                                final C03PacketPlayer packetPlayer = event.getPacket();
                                double x = mc.thePlayer.posX;
                                double y = mc.thePlayer.posY;
                                double z = mc.thePlayer.posZ;
                                float yaw = mc.thePlayer.rotationYaw;
                                float pitch = mc.thePlayer.rotationPitch;
                                final boolean ground = packetPlayer.onGround;

                                if (packetPlayer.isMoving()) {
                                    x = packetPlayer.getPositionX();
                                    y = packetPlayer.getPositionY();
                                    z = packetPlayer.getPositionZ();
                                }

                                if (packetPlayer.getRotating()) {
                                    yaw = packetPlayer.getYaw();
                                    pitch = packetPlayer.getPitch();
                                }

                                if (mc.thePlayer.ticksExisted % 40 == 0) {
                                    packetPlayer.onGround = false;
                                } else if (mc.thePlayer.ticksExisted % 4 != 0) {
                                    event.setCancelled(true);
                                } else if (packetPlayer.getRotating() || yaw != verusYaw || pitch != verusPitch) {
                                    this.verusYaw = packetPlayer.getYaw();
                                    this.verusPitch = packetPlayer.getPitch();
                                    event.setPacket(new C03PacketPlayer.C06PacketPlayerPosLook(x, y, z, yaw, pitch, ground));
                                } else {
                                    event.setPacket(new C03PacketPlayer.C04PacketPlayerPosition(x, y, z, ground));
                                }
                            }
                            break;
                        case VERUS:
                            if (event.getPacket() instanceof C0FPacketConfirmTransaction) {
                                packetQueue.add(event.getPacket());
                                event.setCancelled(true);
                            }
                            if (event.getPacket() instanceof C0BPacketEntityAction) {
                                event.setCancelled(true);
                            }
                            if (event.getPacket() instanceof C03PacketPlayer) {
                                final C03PacketPlayer packetPlayer = event.getPacket();
                                double x = mc.thePlayer.posX;
                                double y = mc.thePlayer.posY;
                                double z = mc.thePlayer.posZ;
                                float yaw = mc.thePlayer.rotationYaw;
                                float pitch = mc.thePlayer.rotationPitch;
                                final boolean ground = packetPlayer.onGround;

                                if (packetPlayer.isMoving()) {
                                    x = packetPlayer.getPositionX();
                                    y = packetPlayer.getPositionY();
                                    z = packetPlayer.getPositionZ();
                                }

                                if (packetPlayer.getRotating()) {
                                    yaw = packetPlayer.getYaw();
                                    pitch = packetPlayer.getPitch();
                                }

                                if (mc.thePlayer.ticksExisted % 40 == 0) {
                                    packetPlayer.y = -0.911F;
                                    packetPlayer.onGround = false;
                                } else if (mc.thePlayer.ticksExisted % 4 != 0) {
                                    event.setCancelled(true);
                                } else if (packetPlayer.getRotating() || yaw != verusYaw || pitch != verusPitch) {
                                    this.verusYaw = packetPlayer.getYaw();
                                    this.verusPitch = packetPlayer.getPitch();
                                    event.setPacket(new C03PacketPlayer.C06PacketPlayerPosLook(x, y, z, yaw, pitch, ground));
                                } else {
                                    event.setPacket(new C03PacketPlayer.C04PacketPlayerPosition(x, y, z, ground));
                                }
                            }
                            break;
                        case LUNAR:
                            if (event.getPacket() instanceof C0BPacketEntityAction)
                                event.setCancelled(true);

                            if (event.getPacket() instanceof C0FPacketConfirmTransaction) {
                                PacketSleepThread.delayPacket(event.getPacket(), 120L);
                                event.setCancelled(true);
                            }

                            if (event.getPacket() instanceof C00PacketKeepAlive) {
                                PacketSleepThread.delayPacket(event.getPacket(), 120L);
                                event.setCancelled(true);
                            }

                            if (event.getPacket() instanceof C03PacketPlayer) {
                                C13PacketPlayerAbilities packetPlayerAbilities = new C13PacketPlayerAbilities();
                                packetPlayerAbilities.setAllowFlying(true);
                                packetPlayerAbilities.setFlying(true);
                                PacketUtil.sendPacketNoEvent(packetPlayerAbilities);
                            }
                            break;
                        case VERUS_COMBAT:
                            if (event.getPacket() instanceof C0FPacketConfirmTransaction) {
                                packetQueue.add(event.getPacket());
                                event.setCancelled(true);
                            } else if (event.getPacket() instanceof C0BPacketEntityAction) {
                                C0BPacketEntityAction packetEntityAction = event.getPacket();
                                if (packetEntityAction.func_180764_b() == C0BPacketEntityAction.Action.START_SPRINTING || packetEntityAction.func_180764_b() == C0BPacketEntityAction.Action.STOP_SPRINTING) {
                                    event.setCancelled(true);
                                }
                            }
                            break;
                        case GHOSTLY: {

                            if (event.getPacket() instanceof C00PacketKeepAlive) {
                                event.setCancelled(true);
                            }

                            if (event.getPacket() instanceof C0BPacketEntityAction) {
                                C0BPacketEntityAction packetEntityAction = event.getPacket();
                                if (packetEntityAction.func_180764_b() == C0BPacketEntityAction.Action.START_SPRINTING || packetEntityAction.func_180764_b() == C0BPacketEntityAction.Action.STOP_SPRINTING) {
                                    event.setCancelled(true);
                                }
                            }

                            if (event.getPacket() instanceof C03PacketPlayer) {
                                PacketUtil.sendPacketNoEvent(new C0CPacketInput(mc.thePlayer.moveStrafing, mc.thePlayer.moveForward, mc.thePlayer.movementInput.jump, mc.thePlayer.movementInput.sneak));
                                final C03PacketPlayer packetPlayer = event.getPacket();
                                double x = mc.thePlayer.posX;
                                double y = mc.thePlayer.posY;
                                double z = mc.thePlayer.posZ;
                                float yaw = mc.thePlayer.rotationYaw;
                                float pitch = mc.thePlayer.rotationPitch;
                                final boolean ground = packetPlayer.onGround;

                                if (packetPlayer.getRotating()) {
                                    yaw = packetPlayer.getYaw();
                                    pitch = packetPlayer.getPitch();
                                }

                                if (packetPlayer.isMoving()) {
                                    x = packetPlayer.getPositionX();
                                    y = packetPlayer.getPositionY();
                                    z = packetPlayer.getPositionZ();
                                }
                                event.setPacket(new C03PacketPlayer.C06PacketPlayerPosLook(x, y, z, yaw, pitch, ground));
                            }
                            break;
                        }

                        case CAVEPVP: {
                            if (event.getPacket() instanceof C00PacketKeepAlive) {
                                event.setCancelled(true);
                            }
                        }
                        break;

                        case FAITHFUL: {
                            if (mc.thePlayer != null && mc.thePlayer.ticksExisted < 5) {
                                this.packetQueue.clear();
                            }

                            if (event.getPacket() instanceof C0BPacketEntityAction) {
                                C0BPacketEntityAction packetEntityAction = event.getPacket();
                                if (packetEntityAction.func_180764_b() == C0BPacketEntityAction.Action.START_SPRINTING || packetEntityAction.func_180764_b() == C0BPacketEntityAction.Action.STOP_SPRINTING) {
                                    event.setCancelled(true);
                                }
                            }

                            if (event.getPacket() instanceof C0FPacketConfirmTransaction) {
                                this.packetQueue.add(event.getPacket());
                                event.setCancelled(true);
                            }

                            if (event.getPacket() instanceof C03PacketPlayer) {
                                final C03PacketPlayer packetPlayer = event.getPacket();
                                double x = mc.thePlayer.posX;
                                double y = mc.thePlayer.posY;
                                double z = mc.thePlayer.posZ;
                                float yaw = mc.thePlayer.rotationYaw;
                                float pitch = mc.thePlayer.rotationPitch;
                                boolean ground = packetPlayer.onGround;

                                if (packetPlayer.isMoving()) {
                                    x = packetPlayer.getPositionX();
                                    y = packetPlayer.getPositionY();
                                    z = packetPlayer.getPositionZ();
                                }

                                event.setPacket(new C03PacketPlayer.C06PacketPlayerPosLook(x, y, z, yaw, pitch, ground));
                            }
                            break;
                        }
//                        case WATCHDOG_NEW:
//                            if (ServerUtils.onHypixel()) {
//                                if (event.getPacket() instanceof C0FPacketConfirmTransaction) {
//                                    C0FPacketConfirmTransaction packetConfirmTransaction = event.getPacket();
//                                    if (packetConfirmTransaction.getUid() < 0) {
//                                        packetQueue.add(event.getPacket());
//                                        event.setCancelled(true);
//                                    }
//                                }
//
//                                if (event.getPacket() instanceof C00PacketKeepAlive) {
//                                    packetQueue.add(event.getPacket());
//                                    event.setCancelled(true);
//                                }
//                            } else {
//                                ChatUtil.displayChatMessage("You have to be on Hypixel to use this mode.");
//                                this.toggle();
//                            }
//                            break;

                        case WATCHDOG:
                            if (ServerUtils.onHypixel()) {
                                if (event.getPacket() instanceof C0FPacketConfirmTransaction) {
                                    C0FPacketConfirmTransaction packetConfirmTransaction = event.getPacket();
                                    if (packetConfirmTransaction.uid < 0) {
                                        if (mc.thePlayer.ticksExisted > 20) {
                                            packetQueue.add(event.getPacket());
                                            event.setCancelled(true);
                                        }
                                    }
                                }

                                if (event.getPacket() instanceof C00PacketKeepAlive) {
                                    if (mc.thePlayer.ticksExisted > 20) {
                                        packetQueue.add(event.getPacket());
                                        event.setCancelled(true);
                                    }
                                }

                                if (event.getPacket() instanceof C03PacketPlayer) {
                                    C03PacketPlayer packetPlayer = event.getPacket();
                                    event.forceCancel(!packetPlayer.isMoving() && !packetPlayer.getRotating());
                                }
                            } else {
                                ChatUtil.displayChatMessage("You have to be on Hypixel to use this mode.");
                                this.toggle();
                            }
                            break;

                        case MINEPLEX:
                            if (event.getPacket() instanceof C00PacketKeepAlive) {
                                C00PacketKeepAlive packetKeepAlive = event.getPacket();
                                packetKeepAlive.key -= 32;
                                event.setPacket(packetKeepAlive);
                            }
                            break;
                    }
                    break;
                case INBOUND: {
                    if (event.getPacket() instanceof S08PacketPlayerPosLook && debug.getValue() && mc.thePlayer.ticksExisted > 20) {
                        ChatUtil.displayChatMessage("Flagged on tick: " + mc.thePlayer.ticksExisted);
                    }
//                    switch (mode) {
//                        case WATCHDOG_NEW:
//                            if (event.getPacket() instanceof S08PacketPlayerPosLook) {
//                                final TeleportCommand teleportCommand = new TeleportCommand();
//                                teleportCommand.flagged = true;
//                            }
//                            break;

//                        case LUNAR:
//                        case VERUS:
//                        case FAITHFUL:
//                            if (event.getPacket() instanceof S08PacketPlayerPosLook) {
//                                final S08PacketPlayerPosLook packetPlayerPosLook = event.getPacket();
//                                NetworkPlayerInfo npi = mc.getNetHandler().func_175102_a(mc.thePlayer.getUniqueID());
//                                if (npi == null)
//                                    break;
//                                double x = packetPlayerPosLook.func_148932_c() - mc.thePlayer.posX;
//                                double y = packetPlayerPosLook.func_148928_d() - mc.thePlayer.posY;
//                                double z = packetPlayerPosLook.func_148933_e() - mc.thePlayer.posZ;
//                                double diff = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
//                                double distance = 22.0D;
//                                if (diff <= distance) {
//                                    PacketUtil.sendPacketNoEvent(new C03PacketPlayer.C06PacketPlayerPosLook(packetPlayerPosLook.func_148932_c(), packetPlayerPosLook.func_148928_d(), packetPlayerPosLook.func_148933_e(), mc.thePlayer.rotationYaw, mc.thePlayer.rotationPitch, true));
//                                    event.setCancelled(true);
//                                }
//                            }
//                            break;
//                    }
                    break;
                }
            }
        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }

    @Override
    public void onEnable() {
        packetQueue.clear();
        stopwatch.resetTime();
        if (enumValue.getValue().equals(Mode.VERUS) || enumValue.getValue().equals(Mode.VERUS2) || enumValue.getValue().equals(Mode.FAITHFUL)) {
            PacketUtil.sendPacket(new C0BPacketEntityAction(mc.thePlayer, C0BPacketEntityAction.Action.STOP_SPRINTING));
        }
        super.onEnable();
    }

    public String getSuffix() {
        return " \2477" + enumValue.getValue().getDisplayName();
    }

    public enum Mode implements INameable {
        FAITHFUL("Old Verus"), AAC("AAC"), MINEPLEX("Mineplex Combat"), VERUS("Verus"), VERUS2("Verus 2"), VERUS_COMBAT("Verus Combat"), GHOSTLY("Ghostly"), WATCHDOG("Watchdog"), SENTINEL("Sentinel"), LUNAR("Lunar"), CAVEPVP("Cave PvP");

        private final String name;

        Mode(String name) {
            this.name = name;
        }

        @Override
        public String getDisplayName() {
            return name;
        }
    }
}